﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Extensil.Common;
using Vibz.TeamAssignment.Common;
using Vibz.TeamAssignment.Common.Entity;
using Vibz.RichTextBox;

namespace Vibz.TeamAssignment
{
    public enum TaskOperation
    {
        EditInNew, AddNew, Edit, AddChild, AddSibling
    }
    public partial class CreateEditAssignment : BaseCategory
    {
        public delegate void CreateUpdateCompleteEventHandler(object sender, EventArgs e);
        public event CreateUpdateCompleteEventHandler CreateUpdateComplete;
        public TaskOperation Operation
        {
            get;
            set;
        }
        public bool ContentChanged
        {
            get;
            set;
        }
        public bool DueDateChanged
        {
            get;
            set;
        }
        BackgroundWorker bwLoader;
        AssignmentClient _aClient;
        TaskGrid tGrid;
        int _parentID = -1;
        internal int _ID = -1;
        Task _parentTask = null;
        Task _currentTask = null;
        TaskAssignment _currentAssignment = null;
        TaskGroup _taskGroup = null;
        bool _taskGroupLoading = false;
        bool _taskLoadComplete = false;
        public CreateEditAssignment()
            : this(TaskOperation.AddNew , - 1)
        {
        }
        public CreateEditAssignment(TaskView taskView)
            : this(TaskOperation.Edit, taskView.Task.TaskID)
        {
            _currentTask = taskView.Task;
            _currentAssignment = taskView.LatestAssignment;
            _taskGroup = taskView.Group;
        }
        // Edit
        public CreateEditAssignment(TaskOperation opr, int taskId)
        {
            InitializeComponent();
            if(LoadClient())
                SetTaskInfo(opr, taskId);

            txtTitle.TextChanged += new EventHandler(txtTitle_TextChanged);
            // rtbTaskDetail.TextChanged += new EventHandler(txtDetails_TextChanged);
            txtEstimatedDuration.TextChanged += new EventHandler(txtEstimatedDuration_TextChanged);
            dtpDueDate.ValueChanged += new EventHandler(dtpDueDate_ValueChanged);
            //txtAssignComment.TextChanged += new EventHandler(txtAssignComment_TextChanged);
            cbExtimatedDuration.SelectedIndexChanged += new EventHandler(cbExtimatedDuration_SelectedIndexChanged);
            cbRequestOrAssignTo.SelectedIndexChanged += new EventHandler(cbRequestOrAssignTo_SelectedIndexChanged);
        }
        
        bool LoadClient()
        {
            try
            {
                _aClient = new AssignmentClient(ReportProgress);
                return true;
            }
            catch(ManagerNotDefinedException exc)
            {
                AlertBox.ShowDialog("You must configure assignment manager to run this application.");
                ReportProgress(100, "You must configure assignment manager to run this application.");
                return false;
            }
            catch(Exception exc)
            {
                AlertBox.ShowDialog(new Exception("Error occured while loading assignment controls. " + exc.Message));
                ReportProgress(100, "Error occured while loading assignment controls. " + exc.Message);
                return false;
            }
        }
        void SetTaskInfo(TaskOperation opr, int taskId)
        {
            Operation = opr;
            ContentChanged = false;
            DueDateChanged = false;
            _currentAssignment = null;
            _currentTask = null;
            _taskGroup = null;
            switch(Operation)
            {
                case TaskOperation.Edit:
                    _parentID = -1;
                    _ID = taskId;
                    break;
                case TaskOperation.AddSibling:
                    _parentID = taskId;
                    _ID = -1;
                    break;
                case TaskOperation.AddChild:
                    _parentID = taskId;
                    _ID = -1;
                    break;
                default:
                case TaskOperation.AddNew:
                    _parentID = -1;
                    _ID = -1;
                    break;
            }
        }
        internal void LoadTaskInfo(TaskOperation opr, int taskId)
        {
            _taskLoadComplete = false;
            tabControl1.SelectTab(0);
            SetTaskInfo(opr, taskId);            
            LoadTask();
            txtTitle.Focus();
        }
        protected override void OnLoad(EventArgs e)
        {
            this.Enabled = false;
            if(_aClient == null)
                return;

            try
            {
                _aClient.Connect();
            }
            catch(ParameterNotDefinedException exc)
            {
                AlertBox.ShowDialog("Configuration incomplete. " + exc.Parameter + " is not defined.");
                ReportProgress(100, "Configuration incomplete. " + exc.Parameter + " is not defined.");
                return;
            }
            catch(Exception exc)
            {
                AlertBox.ShowDialog(new Exception("Error occured while loading assignment controls. " + exc.Message));
                ReportProgress(100, "Error occured while loading assignment controls. " + exc.Message);
                return;
            }
            tGrid = new TaskGrid();
            tGrid.TaskLoadRequired += new TaskGrid.TaskLoadEventHandler(tGrid_TaskLoadRequired);
            tGrid.Dock = DockStyle.Fill;
            tGrid.ShowNewTaskMenu = false;
            tpSubTask.Controls.Add(tGrid);
            tabControl1.TabPages.Remove(tpReporting);
            SetRTBControlVisibility(rtbAssignComment);
            SetRTBControlVisibility(rtbTaskDetail);
            LoadTask();
        }

        void LoadTask()
        {
            rtbAssignComment.Text = "";
            rtbTaskDetail.Text = "";
            txtEstimatedDuration.Text = "";
            txtParentTask.Text = "";
            txtTitle.Text = "";
            dtpDueDate.Value = DateTime.Today;
            if(cbAssignStatus.Items != null)
                cbAssignStatus.Items.Clear();
            if(cbRequestOrAssignTo.Items != null)
                cbRequestOrAssignTo.Items.Clear();
            
            cbRequestOrAssignTo.SelectedIndex = cbRequestOrAssignTo.FindStringExact(AssignmentClient.CurrentUser);
            tGrid.Clear();
            
            // Static
            string[] extDur = new string[] { "Hours", "Days" };
            cbExtimatedDuration.DataSource = extDur.ToList();

            //dtpDueDate.MinDate = DateTime.Now;
            dtpDueDate.MaxDate = DateTime.Now.AddYears(1);

            btnCreateTask.Text = (_ID != -1) ? "Update Task" : "Create Task";

            // Dynamic
            bwLoader = new BackgroundWorker();
            bwLoader.WorkerReportsProgress = true;
            bwLoader.WorkerSupportsCancellation = true;
            bwLoader.DoWork += new DoWorkEventHandler(LoadDynamicControls);
            bwLoader.ProgressChanged += new ProgressChangedEventHandler(bwLoader_ProgressChanged);
            bwLoader.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwLoader_RunWorkerCompleted);
            bwLoader.RunWorkerAsync();
        }

        void bwLoader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            pbLoader.Visible = false;

            if(_ID == -1)
            {
                this.Enabled = true;
                cbRequestOrAssignTo.SelectedIndex = cbRequestOrAssignTo.FindStringExact(AssignmentClient.CurrentUser);
            }

            _taskLoadComplete = true;
        }

        void bwLoader_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            if(e.UserState.GetType() == typeof(KeyValuePair<string, object>))
            {

                KeyValuePair<string, object> op = (KeyValuePair<string, object>)e.UserState;
                switch(op.Key)
                {
                    case "taskStatus":
                        if(op.Value != null)
                        {
                            foreach(string assignStatus in (List<string>)op.Value)
                                cbAssignStatus.Items.Add(assignStatus);
                        }
                        break;
                    case "subTask":
                        if(op.Value != null)
                        {
                            List<TaskView> taskList = (List<TaskView>)op.Value;
                            foreach(TaskView tv in taskList)
                            {
                                tv.Task.TaskDescription = _aClient.RevertRTF(tv.Task.TaskDescription);
                            }
                            tGrid.Load(taskList, _aClient);
                        }
                        break;
                    case "txtParentTask":
                        if(op.Value != null)
                        {
                            _parentTask = (Task)op.Value;
                            txtParentTask.Text = _parentTask.Title;
                            pbViewParent.Tag = _parentTask.TaskID;

                            splitContainer1.Panel1Collapsed = false;
                        }
                        else
                            splitContainer1.Panel1Collapsed = true;
                        break;
                    case "TaskDetails":
                        if(op.Value != null)
                        {
                            _currentTask = (Task)op.Value;

                            txtTitle.Text = _currentTask.Title;

                            rtbTaskDetail.Rtf = _currentTask.TaskDescription;

                            double estDur = 0;
                            if(double.TryParse(_currentTask.EstimatedDuration.ToString(), out estDur))
                            {
                                int rem = 0;
                                double hourInDay = 0;
                                double.TryParse(_aClient.GetConfig(TaskMasterEntry.WorkingHoursInDay), out hourInDay);
                                int days = Math.DivRem((int)estDur, (int)hourInDay , out rem);
                                if(estDur >= hourInDay && rem == 0)
                                {
                                    txtEstimatedDuration.Text = days.ToString();
                                    cbExtimatedDuration.SelectedItem = "Days";
                                }
                                else
                                {
                                    txtEstimatedDuration.Text = estDur.ToString();
                                    cbExtimatedDuration.SelectedItem = "Hours";
                                }
                            }

                            dtpDueDate.Value = _currentTask.DueDate;

                            _taskGroupLoading = true;

                            if(((List<TaskGroup>)cbTaskGroup.DataSource).Where(tg => tg.ID == _currentTask.GroupID).ToList().Count > 0)
                            {
                                cbTaskGroup.SelectedValue = _currentTask.GroupID;
                                Console.WriteLine(DateTime.Now.ToLongTimeString() + "\tUser controls enabled.");
                                this.Enabled = true;
                            }
                            else
                            {
                                List<TaskGroup> tGroup = _aClient.GetAllTaskGroup();
                                cbTaskGroup.Text = tGroup.Where(tg => tg.ID == _currentTask.GroupID).Select(t => t.Title).ToList()[0];
                            }
                            _taskGroupLoading = false;
                        }
                        break;
                    case "cbTaskGroup Fill":
                        if(op.Value != null)
                        {
                            cbTaskGroup.DisplayMember = "Title";
                            cbTaskGroup.ValueMember = "ID";
                            _taskGroupLoading = true;
                            cbTaskGroup.DataSource = (List<TaskGroup>)op.Value;
                            _taskGroupLoading = false;
                        }
                        break;
                    case "cbRequestOrAssignTo Fill":
                        if(op.Value != null)
                        {
                            if(((List<string>)op.Value).Count <= 1)
                                tabControl1.TabPages.Remove(tpAssignment);

                            foreach(string assignTo in (List<string>)op.Value)
                                cbRequestOrAssignTo.Items.Add(assignTo);
                            
                        }
                        break;
                    case "TaskAssignment":
                        if(op.Value != null)
                        {
                            _currentAssignment = (TaskAssignment)op.Value;
                            cbRequestOrAssignTo.SelectedItem = _currentAssignment.AssignedTo;

                            cbAssignStatus.SelectedItem = _currentAssignment.AssignStatus.ToString();
                            ShowAssignToOption(_currentAssignment.AssignStatus.ToString());

                            // Editing of assign comment is not functional requirement
                            // rtbAssignComment.Rtf = tAss.AssignComment;

                            string assText = _currentAssignment.IsRequest ? "Request" : "Assign";
                            lblAssignStatus.Text = assText + "ed by " + _currentAssignment.AssignBy
                                + " to " + _currentAssignment.AssignedTo + " on " + _currentAssignment.AssignRequestDate.ToShortDateString();
                        }
                        break;
                }
            }
            else
                ReportProgress(e.ProgressPercentage, e.UserState.ToString());
        }

        void tGrid_TaskLoadRequired(object sender, TaskLoadEventArgs e)
        {
            LoadTaskInfo(e.Operation, e.TaskID);
        }


        void LoadDynamicControls(object sender, DoWorkEventArgs e)
        {
            try
            {
                bwLoader.ReportProgress(10, new KeyValuePair<string, object>("cbTaskGroup Fill", _aClient.GetUsersTaskGroup()));

                bwLoader.ReportProgress(20, new KeyValuePair<string, object>("cbRequestOrAssignTo Fill", _aClient.GetAllMembers()));
                
                bwLoader.ReportProgress(70,
                    new KeyValuePair<string, object>("taskStatus", _aClient.GetAssignStatusList()));

                if(_ID == -1)
                {
                    bwLoader.ReportProgress(30,
                    new KeyValuePair<string, object>("txtParentTask",
                        (_parentID != -1 ? _aClient.GetTask(_parentID) : null)));
                }
                else
                {
                    Task task = _currentTask == null ? _aClient.GetTask(_ID) : _currentTask;
                    bwLoader.ReportProgress(40,
                        new KeyValuePair<string, object>("TaskDetails", task));

                    bwLoader.ReportProgress(50,
                        new KeyValuePair<string, object>("txtParentTask", _aClient.GetTask(task.ParentID)));

                    TaskAssignment tAss = _currentAssignment == null 
                        ? _aClient.GetLatestAssignment(task.TaskID) : _currentAssignment;
                    bwLoader.ReportProgress(60,
                        new KeyValuePair<string, object>("TaskAssignment", 
                            tAss));

                    bwLoader.ReportProgress(70,
                        new KeyValuePair<string, object>("subTask", _aClient.GetImmediateSubTask(task.TaskID)));

                }
            }
            catch(Exception exc)
            {
                AlertBox.ShowDialog(exc);
            }
        }

        private void btnCreateTask_Click(object sender, EventArgs e)
        {
            SaveTask();
        }
        internal bool SaveTask()
        {
            try
            {
                RequestInit();

                double estDur = 0;
                if(!String.IsNullOrEmpty(txtEstimatedDuration.Text.Trim()) 
                    && !double.TryParse(txtEstimatedDuration.Text, out estDur))
                    throw new Exception("Invalid estimated duration entered.");

                if(DueDateChanged && dtpDueDate.Value.Date.Subtract(DateTime.Today).Days < 0)
                    throw new Exception("Due date of a task can not be less than today.");

                if(_parentTask != null && dtpDueDate.Value.Date.Subtract(_parentTask.DueDate.Date).Days > 0)
                    throw new Exception("Due date of a task can not be greater than due date of its Parent task.");

                if(cbExtimatedDuration.SelectedItem.ToString() == "Days")
                {
                    double hourInDay = 0;
                    double.TryParse(_aClient.GetConfig("WorkingHoursInDay"), out hourInDay);
                    estDur = estDur * hourInDay;
                }

                int tgID = -1;
                if(cbTaskGroup.SelectedItem!=null && ((TaskGroup)cbTaskGroup.SelectedItem).Title != AssignmentClient.PersonalTask)
                    tgID = ((TaskGroup)cbTaskGroup.SelectedItem).ID;

                int pID = -1;
                if(_parentTask != null)
                    pID = _parentTask.TaskID;
                Task task = new Task(pID, txtTitle.Text, rtbTaskDetail.Rtf,
                    dtpDueDate.Value, estDur, tgID, _ID);


                string assignTo = AssignmentClient.CurrentUser;
                if(cbAssignStatus.SelectedItem != null)
                {
                    switch((AssignStatus)Enum.Parse(typeof(AssignStatus), cbAssignStatus.SelectedItem.ToString()))
                    {
                        case AssignStatus.Assigned:
                            // Assign to new assignee
                            if(cbRequestOrAssignTo.SelectedItem != null
                                && ((TaskGroup)cbTaskGroup.SelectedItem).Title != AssignmentClient.PersonalTask)
                                assignTo = cbRequestOrAssignTo.SelectedItem.ToString();
                            break;
                        case AssignStatus.Closed:
                            // Assign to Assigner
                            assignTo = _currentAssignment.AssignBy;
                            break;
                        case AssignStatus.Accepted:
                            // Self assignment
                            break;
                        case AssignStatus.Rejected:
                            // Assign to Assigner
                            assignTo = _currentAssignment.AssignBy;
                            break;
                    }
                }
                string assignStatus = AssignStatus.Assigned.ToString();
                if(cbAssignStatus.SelectedItem != null
                    && ((TaskGroup)cbTaskGroup.SelectedItem).Title != AssignmentClient.PersonalTask)
                    assignStatus = cbAssignStatus.SelectedItem.ToString();

                bwLoader = new BackgroundWorker();
                bwLoader.WorkerReportsProgress = true;
                bwLoader.WorkerSupportsCancellation = true;
                bwLoader.DoWork += new DoWorkEventHandler(CreateUpdateTask);
                bwLoader.ProgressChanged += new ProgressChangedEventHandler(bwLoader_ProgressChanged);
                bwLoader.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwLoader_TaskCreationCompleted);
                bwLoader.RunWorkerAsync(new object[]{ task, assignTo,
                        rtbAssignComment.Rtf, assignStatus});

                // LoadTask();
                ReportProgress(100, "Task Created successfully");

                return true;
            }
            catch(Exception exc)
            {
                AlertBox.ShowDialog(exc.Message);
                return false;
            }
            finally
            {
                RequestExit();
            }
        }
        void CreateUpdateTask(object sender, DoWorkEventArgs e)
        {
            _aClient.CreateTaskAssignment((Task)((object[])e.Argument)[0], _currentTask, _currentAssignment, 
                ((object[])e.Argument)[1].ToString(), ((object[])e.Argument)[2].ToString(), ((object[])e.Argument)[3].ToString());
        }
        void bwLoader_TaskCreationCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if(this.CreateUpdateComplete != null)
                this.CreateUpdateComplete(this, new EventArgs());

            ContentChanged = false;
        }
        void RequestInit()
        {
            pbLoader.Visible = true;
        }
        void RequestExit()
        {
            pbLoader.Visible = false;
        }

        private void pbViewParent_Click(object sender, EventArgs e)
        {
            LoadTaskInfo(TaskOperation.Edit, (int)pbViewParent.Tag);
        }

        private void cbTaskGroup_SelectedIndexChanged(object sender, EventArgs e)
        {
            if(((TaskGroup)cbTaskGroup.SelectedItem).Title == AssignmentClient.PersonalTask)
                tabControl1.TabPages.Remove(tpAssignment);
            else
                tabControl1.TabPages.Insert(1, tpAssignment);
            if(_taskLoadComplete)
                ContentChanged = true;
        }

        private void txtTitle_TextChanged(object sender, EventArgs e)
        {
            if(_taskLoadComplete)
                ContentChanged = true;
        }

        private void txtDetails_TextChanged(object sender, EventArgs e)
        {
            if(_taskLoadComplete)
                ContentChanged = true;
        }

        private void txtEstimatedDuration_TextChanged(object sender, EventArgs e)
        {
            if(_taskLoadComplete)
                ContentChanged = true;
        }

        private void dtpDueDate_ValueChanged(object sender, EventArgs e)
        {
            if(_taskLoadComplete)
            {
                DueDateChanged = true;
                ContentChanged = true;
            }
        }

        private void txtAssignComment_TextChanged(object sender, EventArgs e)
        {
            if(_taskLoadComplete)
                ContentChanged = true;
        }

        private void cbExtimatedDuration_SelectedIndexChanged(object sender, EventArgs e)
        {
            if(_taskLoadComplete)
                ContentChanged = true;
        }

        private void cbRequestOrAssignTo_SelectedIndexChanged(object sender, EventArgs e)
        {
            if(_taskLoadComplete)
                ContentChanged = true;
        }

        private void cbAssignStatus_SelectedIndexChanged(object sender, EventArgs e)
        {
            ShowAssignToOption(cbAssignStatus.SelectedItem.ToString());
        }
        void ShowAssignToOption(string selectedText)
        {
            lblAssignTo.Visible = selectedText == AssignStatus.Assigned.ToString();
            cbRequestOrAssignTo.Visible = selectedText == AssignStatus.Assigned.ToString();
        }
        void SetRTBControlVisibility(VibzRichTextBox rtb)
        {
            rtb.AlignCenterVisible = true;
            rtb.AlignLeftVisible = true;
            rtb.AlignRightVisible = true;
            rtb.BoldVisible = true;
            rtb.BulletsVisible = true;
            rtb.CausesValidation = true;
            rtb.ChooseFontVisible = true;
            rtb.FontColorVisible = true;
            rtb.FontFamilyVisible = true;
            rtb.FontSizeVisible = true;
            rtb.GroupAlignmentVisible = true;
            rtb.GroupBoldUnderlineItalicVisible = true;
            rtb.GroupFontColorVisible = true;
            rtb.GroupFontNameAndSizeVisible = true;
            rtb.ItalicVisible = true;
            rtb.SeparatorAlignVisible = true;
            rtb.SeparatorBoldUnderlineItalicVisible = true;
            rtb.SeparatorFontColorVisible = true;
            rtb.SeparatorFontVisible = true;
            rtb.SeparatorSaveLoadVisible = true;
            rtb.ToolStripVisible = true;
            rtb.UnderlineVisible = true;
            rtb.WordWrapVisible = true;
        }

        private void pbHistory_Click(object sender, EventArgs e)
        {
            AssignmentHistory aHistort = new AssignmentHistory(_aClient, _currentTask.TaskID);
            aHistort.Show();
        }
    }
}
